package movee.manager.core;

import movee.config.AppProperties;
import com.google.common.util.concurrent.RateLimiter;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import jakarta.annotation.PostConstruct;
import java.util.Objects;
import java.util.concurrent.PriorityBlockingQueue;

/**
 *
 *
 * @author movee
 */
@Service
@Slf4j
public class AppTaskRateLimiter implements Runnable {

    private final PriorityBlockingQueue<AppTaskInfo> queue;
    private final RateLimiter rateLimiter;

    private boolean stop = false;
    private final Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").serializeNulls().create();

    public AppTaskRateLimiter(@Qualifier(value = "appScheduledTaskExecutor")
                                       ThreadPoolTaskExecutor taskRateLimiterExecutor,
                              AppProperties appProperties) {

        this.queue = new PriorityBlockingQueue<>(1000, new AppTaskInfoCompartor());
        this.rateLimiter = RateLimiter.create(appProperties.getCmdRateSecond());

        // 启动
        taskRateLimiterExecutor.execute(this);
    }

    public void submit(AppTaskInfo info) {
        if (Objects.nonNull(info)) {
            queue.put(info);
        }
    }

    @Override
    public void run() {
        while (!stop) {
            AppTaskInfo unit = null;
            try {
                // 阻塞获取任务
                unit = queue.take();

                // 阻塞获取令牌
                rateLimiter.acquire();

                // do something
            } catch (InterruptedException t) {
                stop = true;
                log.info("exit for InterruptedException");
            } catch (Throwable t) {
                log.error("rate limit failed. BackupTaskInfo: {}, exception info: {}",
                        gson.toJson(unit), ExceptionUtils.getStackTrace(t));
            }
        }
    }

    @PostConstruct
    public void setSelfToOtherBean() {
        // do something
    }

}
